﻿using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Co9320.NamaAlert.Model;
using Co9320.NamaAlert;
using System.Data.SqlServerCe;

namespace TagServiceTest
{
	[TestClass]
	public class LocalDatabaseControllerTest
	{
		public LocalDatabaseControllerTest()
		{
			//
			// TODO: コンストラクタ ロジックをここに追加します
			//
		}

		private TestContext testContextInstance;
		private static int IDSeed;

		private LocalDatabaseController Target;
		private SqlCeCommand Cmd;


		/// <summary>
		///現在のテストの実行についての情報および機能を
		///提供するテスト コンテキストを取得または設定します。
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region 追加のテスト属性
		//
		// テストを作成する際には、次の追加属性を使用できます:
		//
		// クラス内で最初のテストを実行する前に、ClassInitialize を使用してコードを実行してください
		[ClassInitialize()]
		public static void MyClassInitialize(TestContext testContext)
		{
			LocalDatabaseController.CreateDatabase("Target.sdf", true);
			IDSeed = 0;
		}

		[TestInitialize()]
		public void MyTestInitialize()
		{
			Target = new LocalDatabaseController("Target.sdf");
			SqlCeConnection con = new SqlCeConnection("Data Source=Target.sdf");
			con.Open();

			Cmd = con.CreateCommand();
			CreateCommand(Cmd);

			Cmd.CommandText = "DELETE FROM Bind;";
			Cmd.ExecuteNonQuery();

			Cmd.CommandText = "DELETE FROM LiveInfo;";
			Cmd.ExecuteNonQuery();

			Cmd.CommandText = "DELETE FROM Tags;";
			Cmd.ExecuteNonQuery();

		}

		private void CreateCommand(SqlCeCommand cmd)
		{
			Cmd.Parameters.Add("@sid", System.Data.SqlDbType.NVarChar);
			Cmd.Parameters.Add("@cstr", System.Data.SqlDbType.NVarChar);
			Cmd.Parameters.Add("@tag", System.Data.SqlDbType.NVarChar);
			Cmd.Parameters.Add("@tid", System.Data.SqlDbType.BigInt);
			Cmd.Parameters.Add("@lid", System.Data.SqlDbType.BigInt);
		}


		[TestCleanup()]
		public void MyTestCleanup()
		{
			Target.Dispose();
			Cmd.Dispose();
		}

		#endregion

		[TestMethod]
		public void TableExistsTest()
		{
			TableExistsTest("Bind");
			TableExistsTest("LiveInfo");
			TableExistsTest("SystemInfo");
			TableExistsTest("Tags");
		}

		private void TableExistsTest(string TableName)
		{
			Cmd.CommandText = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=@tbl";
			Cmd.Parameters.Add("@tbl", System.Data.SqlDbType.NVarChar);
			SqlCeParameter param = Cmd.Parameters["@tbl"];
			int Ret = 0;

			param.Value = TableName;
			Ret = (int)Cmd.ExecuteScalar();
			Assert.AreEqual<int>(1, Ret);
			Cmd.Parameters.Clear();
		}

		[TestMethod]
		public void AddTagTest()
		{
			List<TagModel> tags = CreateSampleTags();

			Target.Add("TargetStation", "TargetCaster", tags);

			Cmd.CommandText = "SELECT COUNT(*) FROM Tags";
			Assert.AreEqual(1, Cmd.ExecuteScalar());

			Cmd.CommandText = "SELECT COUNT(*) FROM LiveInfo WHERE StationID='TargetStation' AND Caster='TargetCaster';";
			Assert.AreEqual(1, Cmd.ExecuteScalar());

			AreEqual("TargetStation", "TargetCaster", "My");
		}

		[TestMethod]
		public void AddTagNullExpreTest()
		{
			List<TagModel> tags = CreateSampleTags();
			tags.Add(new TagModel(null, TagKind.Self));

			Target.Add("TargetStation", "TargetCaster", tags);

			AreEqual("TargetStation", "TargetCaster", "My");
			Cmd.CommandText = "SELECT COUNT(*) FROM Tags;";
			var Ret = Cmd.ExecuteScalar();
			Assert.AreEqual(1, Ret);
		}

		[TestMethod]
		public void PreventDuplicateTest()
		{
			List<TagModel> tags = new List<TagModel>();
			tags.Add(new TagModel("My", TagKind.Self));
			tags.Add(new TagModel("My", TagKind.Self));

			Target.Add("Station", "Caster", tags);
			AreEqual("Station", "Caster", "My");
		}

		[TestMethod]
		public void PriventMultiAsMultiTransaction()
		{
			var tags = CreateSampleTags();

			Target.Add("StationA", "CasterA", tags);
			Target.Add("StationA", "CasterA", tags);

			AreEqual("StationA", "CasterA", "My");
		}

		[TestMethod]
		public void DeleteTest()
		{
			var tags = CreateSampleTags();
			Target.Add("StationB", "CasterB", tags);

			AreEqual("StationB", "CasterB", "My");

			Target.Delete("StationB", "CasterB", tags);

			AreEqual("StationB", "CasterB", "My", 0);
			AreEqual("StationB", "CasterB", "Cstr", 0);
		}

		[TestMethod]
		public void DeleteNullTest()
		{
			var tags = CreateSampleTags();
			Target.Add("StationC", "CasterC", tags);

			AreEqual("StationC", "CasterC", "My");

			tags.Add(new TagModel("My", TagKind.Self));
			Target.Delete("StationC", "CasterC", tags);

			AreEqual("StationC", "CasterC", "My", 0);
		}

		[TestMethod]
		public void GetTest()
		{
			var tags = CreateSampleTags();
			string sid = GetID("sid");
			string cstr = GetID("cstr");

			Target.Add(sid, cstr, tags);
			var Ret = Target.GetTag(sid, cstr);
			Assert.AreEqual(1, Ret.Count);
			Assert.AreEqual("My", Ret[0].Value);
		}

		[TestMethod]
		public void GetTestNull()
		{
			var tags = CreateSampleTags();
			var sid = GetID("sid");
			var cstr = GetID("cstr");

			Target.Add(sid, cstr, tags);

			var Ret = Target.GetTag(null, null);
			Assert.AreEqual<int>(0, Ret.Count);
		}

		[TestMethod]
		public void ShallowShrinkTest()
		{
			List<TagModel> tags = CreateSampleTags();
			var sid = GetID("sid");
			var cstr = GetID("cstr");

			Target.Add(sid, cstr, tags);

			var isolsid = GetID("IsolSid");
			var isolcstr = GetID("IsolCstr");

			tags.Clear();
			tags.Add(new TagModel(GetID("IsolTag"), TagKind.Self));

			Target.Add(isolsid, cstr, tags);
			Target.Delete(isolsid, cstr, tags);

			StringBuilder bld = new StringBuilder();
			bld.Append("UPDATE SystemInfo SET ParamValue=");
			bld.Append("'");
			bld.Append((DateTime.Now - new TimeSpan(40, 0, 0, 0)).ToString());
			bld.Append("' ");
			bld.Append(" WHERE ParamName='RecentShallowShrink'");
			bld.Append(";");
			Cmd.CommandText = bld.ToString();
			Cmd.ExecuteNonQuery();

			Target.Dispose();
			Target = new LocalDatabaseController("Target.sdf");

			AreEqual(isolsid, isolcstr, tags[0].Value, 0);
			AreEqual(sid, cstr, "My", 1);

		}

		[TestMethod]
		public void ErrorGetTest()
		{
			var ret = Target.GetTag(null, null);
			Assert.AreEqual<int>(0, ret.Count);

			ret = Target.GetTag("hoge", null);
			Assert.AreEqual<int>(0, ret.Count);

			ret = Target.GetTag(null, "piyo");
			Assert.AreEqual<int>(0, ret.Count);

			ret = Target.GetTag("", "");
			Assert.AreEqual(0, ret.Count);

			ret = Target.GetTag("hoge", "");
			Assert.AreEqual<int>(0, ret.Count);

			ret = Target.GetTag("", "piyo");
			Assert.AreEqual<int>(0, ret.Count);
		}

		[TestMethod]
		[DeploymentItem("TagService.dll")]
		public void GetSchemaVersionTest()
		{
			PrivateObject priv = new PrivateObject(Target);
			LocalDatabaseController_Accessor acc = new LocalDatabaseController_Accessor(priv);

			Assert.AreEqual<int>(0, acc.info.SchemaMajor);
			Assert.AreEqual<int>(1, acc.info.SchemaMinor);
		}

		[TestMethod]
		public void FileterTest()
		{
			Cmd.CommandText = "DELETE FROM LiveInfo;";
			Cmd.ExecuteNonQuery();

			Cmd.CommandText = "DELETE FROM Tags;";
			Cmd.ExecuteNonQuery();

			Cmd.CommandText = "DELETE FROM Bind;";
			Cmd.ExecuteNonQuery();

			List<TagModel> tags = new List<TagModel>();
			tags.Add(new TagModel("hoge", TagKind.Self));
			tags.Add(new TagModel("01234567890123456789", TagKind.Self));
			tags.Add(new TagModel("012345678901234567890", TagKind.Self));
			tags.Add(new TagModel("			", TagKind.Self));
			tags.Add(new TagModel("", TagKind.Self));

			Target.Add("Station", "Caster", tags);

			var Expected = Target.GetTag("Station", "Caster");

			Assert.AreEqual<int>(2, Expected.Count);
			Assert.AreEqual<string>("hoge", Expected[0].Value);
			Assert.AreEqual<string>("01234567890123456789", Expected[1].Value);

		}


		private List<TagModel> CreateSampleTags()
		{
			List<TagModel> tags = new List<TagModel>();
			tags.Add(new TagModel("My", TagKind.Self));
			tags.Add(new TagModel("Usr", TagKind.User));
			tags.Add(new TagModel("Cstr", TagKind.Caster));
			tags.Add(new TagModel("None", TagKind.None));

			return tags;
		}

		private void AreEqual(string StationID, string Caster, string TagValue)
		{
			AreEqual(StationID, Caster, TagValue, 1);
		}


		private void AreEqual(string StationID, string Caster, string TagValue, int Count)
		{
			object lid, tid;

			Cmd.CommandText = "SELECT ID FROM LiveInfo WHERE StationID=@sid AND Caster=@cstr;";
			Cmd.Parameters["@sid"].Value = StationID;
			Cmd.Parameters["@cstr"].Value = Caster;
			lid = Cmd.ExecuteScalar();

			Cmd.CommandText = "SELECT ID FROM Tags WHERE Value=@tag;";
			Cmd.Parameters["@tag"].Value = TagValue;
			tid = Cmd.ExecuteScalar();

			if (Count != 0)
			{
				Assert.IsNotNull(tid);
				Assert.IsNotNull(lid);
			}
			else
			{
				return;
			}

			Cmd.CommandText = "SELECT COUNT(*) FROM Bind WHERE LiveInfoId=@lid AND TagsId=@tid;";
			Cmd.Parameters["@lid"].Value = lid;
			Cmd.Parameters["@tid"].Value = tid;

			Assert.AreEqual(Count, Cmd.ExecuteScalar());
		}

		private string GetID(string Prefix)
		{
			if (Prefix == null)
			{
				return IDSeed++.ToString();
			}
			else
			{
				return string.Format("{0}_{1}", Prefix, IDSeed++);
			}
		}

	}
}